package finn.movingheadtracker;

import java.net.SocketException;
import java.util.List;

import artnet4j.ArtNet;
import artnet4j.ArtNetException;
import artnet4j.ArtNetNode;
import artnet4j.ArtNetServer;
import artnet4j.events.ArtNetDiscoveryListener;
import artnet4j.events.ArtNetServerListener;
import artnet4j.packets.ArtDmxPacket;
import artnet4j.packets.ArtNetPacket;
import artnet4j.packets.PacketType;

public class Artnet implements ArtNetDiscoveryListener{
	static ArtNet artnet;
	static ArtnetThread artnetThread;
	
	public Artnet() {
		artnetThread = new ArtnetThread();
		(new Thread(artnetThread)).start();
	}

	public static void receiveDmx(int universe_id, int subnet_id, byte[] values){
		DmxMerger.setArtnetInput(universe_id, subnet_id, values);
	}
	

	@Override
	public void discoveredNewNode(ArtNetNode node) {
		// TODO Auto-generated method stub
		
	}

	@Override
	public void discoveredNodeDisconnected(ArtNetNode node) {
		// TODO Auto-generated method stub
		
	}

	@Override
	public void discoveryCompleted(List<ArtNetNode> nodes) {
		// TODO Auto-generated method stub
		
	}

	@Override
	public void discoveryFailed(Throwable t) {
		// TODO Auto-generated method stub
		
	}
	
	protected static class ArtnetThread implements Runnable, ArtNetServerListener{
		public static boolean stop = false;
		public static ArtNet artnet;
		
		/**
		 * Provides SequenceIDs for every Artnet Universe/Subnet
		 * @author Finn Hermeling
		 *
		 */
		public static class SequenceID{
			static int[] IDs = new int[32768];
			private static int justGetSequenceID(int absolute){
				return IDs[absolute];
			}
			private static void increaseSequenceID(int absolute){
				int old = IDs[absolute];
				if(old==255){
					old=0;
				}
				else{
					IDs[absolute] = old++;
				}
			}
			public static int getSequenceID(int universe_id, int subnet_id){
				int absolute = universe_id * 16 + subnet_id;
				int sequenceID = justGetSequenceID(absolute);
				increaseSequenceID(absolute);
				return sequenceID;
			}
		}
		
		//TODO Add Artnet Start Exceptions
		@Override
		public void run() {
			artnet = new ArtNet();
			try {
				artnet.start();
			} catch (SocketException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
				return;
			} catch (ArtNetException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
				return;
			}
			artnet.addServerListener(this);
			while(!stop){
				List<Universe> lst = DmxMerger.getOutputUniverses(Universe.ARTNET);
				for(Universe un:lst){
					this.sendDmx(((UniverseArtnet)un).ArtnetUniverseId, ((UniverseArtnet)un).SubnetUniverseId, ((UniverseArtnet)un).values, 512);
				}
				try {
					Thread.sleep(500);
				} catch (InterruptedException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}
			
			artnet.stop();
			
		}
		
		public void sendDmx(int universe_id, int subnet_id, byte[] values, int highest){
			ArtDmxPacket ap = new ArtDmxPacket();
			ap.setUniverse(subnet_id, universe_id);
			ap.setNumChannels(highest);
			ap.setDMX(values, values.length);
			ap.setSequenceID(SequenceID.getSequenceID(universe_id, subnet_id));
			artnet.broadcastPacket(ap);
		}

		@Override
		public void artNetPacketBroadcasted(ArtNetPacket packet) {
			System.out.println("Action 1:");
			
		}

		@Override
		public void artNetPacketReceived(ArtNetPacket packet) {
			if(packet.getType() == PacketType.ART_OUTPUT){
				Artnet.receiveDmx(((ArtDmxPacket)packet).getUniverseID(), ((ArtDmxPacket)packet).getSubnetID(), ((ArtDmxPacket)packet).getDmxData());
			}
			else{
				System.out.println("Received not an Dmx Packet");
			}
			
		}

		@Override
		public void artNetPacketUnicasted(ArtNetPacket packet) {
			System.out.println("Action 3:");
			
		}

		@Override
		public void artNetServerStarted(ArtNetServer server) {
			System.out.println("Action 4:");
			
		}

		@Override
		public void artNetServerStopped(ArtNetServer server) {
			System.out.println("Action 5:");
			
		}
	}
}
